#ifndef _PFC_PROFILER_H_
#define _PFC_PROFILER_H_

#ifdef _WINDOWS

#include <intrin.h>
namespace pfc
{
    class profiler_static
    {
    public:
        profiler_static(const char * p_name);
        ~profiler_static();
        void add_time(t_int64 delta)
        {
            total_time+=delta;
            num_called++;
        }
    private:
        const char * name;
        t_uint64 total_time,num_called;
    };

    class profiler_local
    {
    public:
        profiler_local(profiler_static * p_owner)
        {
            owner = p_owner;
            start = __rdtsc();
        }
        ~profiler_local()
        {
            t_int64 end = __rdtsc();
            owner->add_time(end-start);
        }
    private:
        t_int64 start;
        profiler_static * owner;
    };

#define profiler(name) \
	static pfc::profiler_static profiler_static_##name(#name); \
	pfc::profiler_local profiler_local_##name(&profiler_static_##name);


    class hires_timer
    {
    public:
        void start()
        {
            m_start = g_query();
        }
        double query() const
        {
            return _query( g_query() );
        }
        double query_reset()
        {
            t_uint64 current = g_query();
            double ret = _query(current);
            m_start = current;
            return ret;
        }
    private:
        double _query(t_uint64 p_val) const
        {
            return (double)( p_val - m_start ) / (double) g_query_freq();
        }
        static t_uint64 g_query()
        {
            LARGE_INTEGER val;
            if (!QueryPerformanceCounter(&val)) throw pfc::exception_not_implemented();
            return val.QuadPart;
        }
        static t_uint64 g_query_freq()
        {
            LARGE_INTEGER val;
            if (!QueryPerformanceFrequency(&val)) throw pfc::exception_not_implemented();
            return val.QuadPart;
        }
        t_uint64 m_start;
    };

    class lores_timer
    {
    public:
        void start()
        {
            _start(GetTickCount());
        }

        double query() const
        {
            return _query(GetTickCount());
        }
        double query_reset()
        {
            t_uint32 time = GetTickCount();
            double ret = _query(time);
            _start(time);
            return ret;
        }
    private:
        void _start(t_uint32 p_time)
        {
            m_last_seen = m_start = p_time;
        }
        double _query(t_uint32 p_time) const
        {
            t_uint64 time = p_time;
            if (time < (m_last_seen & 0xFFFFFFFF)) time += 0x100000000;
            m_last_seen = (m_last_seen & 0xFFFFFFFF00000000) + time;
            return (double)(m_last_seen - m_start) / 1000.0;
        }
        t_uint64 m_start;
        mutable t_uint64 m_last_seen;
    };
}
#else
//PORTME
#endif

#endif
